var AjaxAction = {
	/*action, param..., (callback_fn)*/
	//如果是AjaxAction.call(action, param, ..., function(rt){})，异步，结果传入回调函数中。
	//如果是AjaxAction.call(action, param, ...)，则同步，结果直接返回。
	call:function(){
		var asyn = false;
		var cbFn = null;
		var pnum=arguments.length;
		if(typeof arguments[arguments.length-1] == 'function'){
			cbFn = arguments[arguments.length-1];
			asyn = true;
			--pnum;
		}
		
		var sendData = {};
		sendData["id"] = ++al_action_call_id;
		sendData["method"] = arguments[0];
		sendData["params"] = [];
		for(var i=1; i<pnum; ++i){
			sendData["params"].push(arguments[i]);
		}
		try{
			var rt;
			var oXmlHttp = GetHttpRequest();
			var onreadystatechange = function(){ 
		        if ( oXmlHttp.readyState == 4 ){
		            if ( oXmlHttp.status == 200 || oXmlHttp.status == 304 ){
		            	alert(oXmlHttp.responseText);
		                eval('rt = ' + oXmlHttp.responseText);
		                //oXmlHttp.onreadystatechange = null;
		                oXmlHttp = null;
		                if(rt.error)throw rt.error.msg;
		                rt = AjaxAction._loadData(rt['result'], asyn);
		                if(cbFn){
		                	cbFn(rt);
		                }
		            }else{ 
		                //throw ( 'XML request error: ' + oXmlHttp.statusText + ' (' + oXmlHttp.status + ')' ) ; 
		            } 
		        } 
		    };
		    if(asyn){
		    	oXmlHttp.onreadystatechange = onreadystatechange//.closure();
		    	//oXmlHttp.onreadystatechange = function (){
		    	//	if ( oXmlHttp.readyState == 4 ){eval('rt = ' + oXmlHttp.responseText);oXmlHttp = null;}};
		    }
		    var act = window.ALPHA_DEBUG ? "&action="+arguments[0] : "";
		    alert(toJSON(sendData));
			oXmlHttp.open('POST', "TOTEM_RPC.ashx?_TOTEM_RPC_=TOTEM-RPC"+act, asyn);
			oXmlHttp.send(toJSON(sendData));
			
			// firefox 1.5 doesn't fire statechange for sync requests
			if(!asyn){
				onreadystatechange();
			}
			
			return rt;
		}catch(e){
			showDebugInfo(e);
		}
	},
	/*action, param...*/
	syncCall:function(){
		return this.call.apply(this,arguments);
		/*
		var argus = new Array();
		for(var i=0; i<arguments.length; ++i){
			argus[i] = 'arguments['+i+']';
		}
		return eval('this.call(' + argus + ')');
		//*/
	},
	
	_loadData:function(result, asynchronous){
		if(result){
			if(result.toString().substr(0,5) != "<xml>")
				return result;
				
			var data = createXML();
			data.loadXML(result);
			//load page
			var page = data.documentElement.selectNodes('page');
			if(page.length > 0){
				page = page[0];
				if(asynchronous==false){
					document.open();
					document.write(page.text);
					document.close();
				}else{
					document.write(page.text);
				}
				//document.body.innerHTML = page.text;
			}
			
			//装载数据
			var dataview = data.selectNodes('//dataview');
			if(dataview.length > 0){
				dataview = dataview[0];
				var cs = dataview.childNodes;
				for(var i=0; i<cs.length; ++i){
					//eval(cs[i].tagName).loadData(cs[i]);
					window[cs[i].nodeName].loadData(cs[i]);
				}
			}
		}
		return result;
	}
}


//只适用于IE。
function sleep(timeout) {
	window.showModalDialog("javascript:document.writeln('<script>window.setTimeout(function () { window.close(); }, " + timeout + ");<\/script>');");
}

var FormAction = {
	call: function() {
		var asyn = false;
		var cbFn = null;
		if(typeof arguments[arguments.length-1] == 'function'){
			cbFn = arguments[arguments.length-1];
			asyn = true;
		}
		form = $$(arguments[0]);
		stopEvent();
		//处理文件上传
		if(form.enctype == "multipart/form-data"){
			loadSysJS("private/upload/ajaxupload.js");
			
			var w = document.createElement("<div style='z-index:1000'>");
			w.style.position = 'absolute';
			w.style.left = document.body.clientWidth/2 - 110;
			w.style.width = 220;
			w.style.top = document.body.clientHeight/2 - 30;
			w.style.height = 60;
			w.style.lineHeight = '60px';
			w.style.backgroundColor = 'white';
			w.style.textAlign = 'center';
			w.innerHTML = '<img src="'+getLibURI()+'default/image/wait.gif"/>'+'<h3>文件上传中，请等待......</h3>';
			//document.body.appendChild(w);
			
			var uploading = true;
			var form_action = $A(form,'action'); //文件上传后该form的action会被改变，所以需要恢复。
			$.ajaxUpload({
	            uploadform: form,
	            url: './?_FILE_UPLOAD_=FILEUPLOAD',
	            secureuri: false,
	            dataType: 'html',
	            success: function (data) {
	            		$A(form, 'action', form_action); //恢复form的action。
	            		//document.body.removeChild(w);
	            		if(data.indexOf("@error=oversize")==0){
	            			alert("文件大小超出限制。")
	            			if(cbFn)cbFn(true)
	            		}else{
		                    var fileNames = data.split(";");
							fileNames.splice(fileNames.length-1, 1);  //去除最后一个空元素.
							
							for(var i=0, j=0; i<form.all.length; ++i){
								if(form.all[i].type == 'file'){
									form.all[i].path = fileNames[j++];
								}
							}
							uploading = false;
							return FormAction._post(form, cbFn);
	            		}
	                },
	            error: function (msg, status, e) {
	                 alert("上传文件错误："+e.description);
	                 uploading = false;
	                }
	          });
			
			//while(uploading)sleep(100);
		}else{
			return this._post(form, cbFn);
		}
	},
	

	syncCall:function(form){
		return this.call(form);
	},
	
	_post:function(form, cbFn){
		var str = cbFn ? ", cbFn)" : ")";
		var params = this._getParams(form);
		if(params.length > 0){
			var argus = [];
			for(var i=0; i<params.length; ++i){
				argus[i] = 'params['+i+']';
			}
			return eval("AjaxAction.call('" + $A(form,'action') + "'," + argus + str);
		}else{
			return eval("AjaxAction.call('" + $A(form,'action') + "'" + str);
		}
	},
	
	_getParams: function(form) {
		var params = [];
		var count = $A(form, 'bean').split(';').length;
		for(var i=0; i<count; ++i){
			params[i] = {};
		}
		
		fChildren = this._findAllFields(form);
		for(var i=0, n=fChildren.length; i<n; ++i){
			var fld = $A(fChildren[i], 'field');
			var value = this._getValue(fChildren[i]);
			if(value == '')
				value = null;
				
			fs = fld.split(';');
			if(fs.length == 1){
				var f = fs[0].split(':');
				var pi = (f.length==1) ? 0 : (parseInt(f[0])-1);
				if(f[f.length-1] == 'this'){
					params[pi] = value;
				}else if(f[f.length-1].match(/this.\d+/)){
					if(!params[pi] || params[pi].length==undefined)
						params[pi] = [];
					params[pi][f[f.length-1].substring(5)] = value;
				}else{
					params[pi][f[f.length-1]] = value;
				}
			} else {
				for(var j=0; j<fs.length; ++j){
					var f = fs[j].split(':');
					var pi = parseInt(f[0])-1;
					if(f[f.length-1] == 'this'){
						params[pi] = value;
					}else if(f[f.length-1].match(/this.\d+/)){
						if(!params[pi] || params[pi].length==undefined)
							params[pi] = [];
						params[pi][f[f.length-1].substring(5)] = value;
					}else{
						params[pi][f[f.length-1]] = value;
					}
				}
			}
		}
		
		return params;
	},
	
	_getValue:function(obj){
		if(obj.type == "checkbox"){
			return obj.checked?1:0;
		}else if(obj.type == "file"){
			return obj.path;
		}else if(obj.group == "radio"){
			var radios = findElementsBy(obj, "type", "radio");
			for(var i=0; i<radios.length; ++i){
				if(radios[i].checked)
					return radios[i].value;
			}
			return null;
		}else if(obj.group == "checkbox"){
			var box = findElementsBy(obj, "type", "checkbox");
			var vs = [];
			for(var i=0; i<box.length; ++i){
				if(box[i].checked){
					vs.push(box[i].value);
				}
			}
			return vs;
		}else if(obj.tagName == "SELECT"){
			var c = obj.firstChild;
			var vs;
			if(obj.size <= 1){
				while(c != null){
					if(c.selected){
						vs = c.value;
						break;
					}
					c = c.nextSibling;
				}
			}else {
			 vs = [];
				while(c != null){
					if(c.selected){
						vs.push(c.value);
					}
					c = c.nextSibling;
				}
			}
			return vs;
		}else{
			return obj.value;
		}
	},
	
	_findAllFields:function(parent){
		return $(parent).find('[@field]');
		/*
		var fields = [];
		var all = parent.all;
		for(var i=0; i<all.length; ++i){
			if($A(all[i], 'field'))
				fields.push(all[i]);
		}
		
		return fields;
		//*/
	}
};


var al_action_call_id = 0;
function escapeJSONString(s)
{
    /* The following should suffice but Safari's regex is b0rken
       (doesn't support callback substitutions)
       return "\"" + s.replace(/([^\u0020-\u007f]|[\\\"])/g,
       escapeJSONChar) + "\"";
    */

    /* Rather inefficient way to do it */
    var parts = s.split("");
    for(var i=0; i < parts.length; i++) {
	var c =parts[i];
	if(c == '"' ||
	   c == '\\' ||
	   c.charCodeAt(0) < 32 ||
	   c.charCodeAt(0) >= 128)
	    parts[i] = escapeJSONChar(parts[i]);
    }
    return "\"" + parts.join("") + "\"";
};
function escapeJSONChar(c)
{
    if(c == "\"" || c == "\\") return "\\" + c;
    else if (c == "\b") return "\\b";
    else if (c == "\f") return "\\f";
    else if (c == "\n") return "\\n";
    else if (c == "\r") return "\\r";
    else if (c == "\t") return "\\t";
    var hex = c.charCodeAt(0).toString(16);
    if(hex.length == 1) return "\\u000" + hex;
    else if(hex.length == 2) return "\\u00" + hex;
    else if(hex.length == 3) return "\\u0" + hex;
    else return "\\u" + hex;
};
function toJSON(o)
{
    if(o == null) {
	return "null";
    } else if(o.constructor == String) {
	return escapeJSONString(o);
    } else if(o.constructor == Number) {
	return o.toString();
    } else if(o.constructor == Boolean) {
	return o.toString();
    } else if(o.constructor == Date) {
	return '{javaClass: "java.util.Date", time: ' + o.valueOf() +'}';
    } else if(o.constructor == Array) {
	var v = [];
	for(var i = 0; i < o.length; i++) v.push(toJSON(o[i]));
	return "[" + v.join(", ") + "]";
    } else {
	var v = [];
	for(attr in o) {
	    if(o[attr] == null) v.push("\"" + attr + "\": null");
	    else if(typeof o[attr] == "function"); /* skip */
	    else v.push(escapeJSONString(attr) + ": " + toJSON(o[attr]));
	}
	return "{" + v.join(", ") + "}";
    }
};